#ifndef BASE64_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define BASE64_H_62B23520_7C8E_11DE_8A39_0800200C9A66

#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
#pragma once
#endif

#include <string>
#include <vector>

namespace YAML {
class Node;

std::string EncodeBase64(const unsigned char *data, std::size_t size);
std::vector<unsigned char> DecodeBase64(const std::string& input);

class Binary {
public:
	Binary() :
			m_unownedData(0), m_unownedSize(0) {
	}
	Binary(const unsigned char *data, std::size_t size) :
			m_unownedData(data), m_unownedSize(size) {
	}

	bool owned() const {
		return !m_unownedData;
	}
	std::size_t size() const {
		return owned() ? m_data.size() : m_unownedSize;
	}
	const unsigned char *data() const {
		return owned() ? &m_data[0] : m_unownedData;
	}

	void swap(std::vector<unsigned char>& rhs) {
		if (m_unownedData) {
			m_data.swap(rhs);
			rhs.clear();
			rhs.resize(m_unownedSize);
			std::copy(m_unownedData, m_unownedData + m_unownedSize, &rhs[0]);
			m_unownedData = 0;
			m_unownedSize = 0;
		} else {
			m_data.swap(rhs);
		}
	}

	bool operator ==(const Binary& rhs) const {
		const std::size_t s = size();
		if (s != rhs.size())
			return false;
		const unsigned char *d1 = data();
		const unsigned char *d2 = rhs.data();
		for (std::size_t i = 0; i < s; i++) {
			if (*d1++ != *d2++)
				return false;
		}
		return true;
	}

	bool operator !=(const Binary& rhs) const {
		return !(*this == rhs);
	}

private:
	std::vector<unsigned char> m_data;
	const unsigned char *m_unownedData;
	std::size_t m_unownedSize;
};

void operator >>(const Node& node, Binary& binary);
}

#endif // BASE64_H_62B23520_7C8E_11DE_8A39_0800200C9A66
